
#include "IRound.h"

using namespace BWE;

IRound::IRound()
{
	halfPI = PIf * 0.5f;
}
IRound::~IRound()
{

}

void IRound::createPoints(const BRectf& rect, BPointfArray& points)
{
	points.reset();
	createLeftTopPoints(rect, points);
	createRightTopPoints(rect, points);
	createRightBottomPoints(rect, points);
	createLeftBottomPoints(rect, points);
}
void IRound::createLeftTopPoints(const BRectf& rect, BPointfArray& points)
{
	float radiusX = (float)(radiusLeftTop.width() - rect.left());
	float radiusY = (float)(radiusLeftTop.height() - rect.top());
	if (radiusX <= 0 || radiusY <= 0)
	{
		points.append(rect.leftTop());
	}
	else
	{
		if (radiusX == radiusY)
		{
			int sides = (int)bLimit(radiusX / 3, 3, 24);
			float sr = halfPI / sides;
			for (int i = 0; i <= sides; i++)
			{
				float angle = PIf - i * sr;
				float x = cos(angle) * radiusX;
				float y = sin(angle) * radiusX;
				points.append(centerLeftTop + BPointf(x, -y));
			}
		}
		else
		{
			float rx2 = radiusX * radiusX;
			float ry2 = radiusY * radiusY;
			for (float x = -radiusX; x < 0; x += 2)
			{
				float y = sqrt((1.0f - (x * x) / rx2) * ry2);
				points.append(centerLeftTop + BPointf(x, -y));
			}
			points.append(centerLeftTop + BPointf(0, -radiusY));
		}
	}
}
void IRound::createLeftBottomPoints(const BRectf& rect, BPointfArray& points)
{
	float radiusX = (float)(radiusLeftBottom.width() - rect.left());
	float radiusY = (float)(radiusLeftBottom.height() - (widgetSize.height() - rect.bottom()));
	if (radiusX <= 0 || radiusY <= 0)
	{
		points.append(rect.leftBottom());
	}
	else
	{
		if (radiusX == radiusY)
		{
			int sides = (int)bLimit(radiusX / 3, 3, 24);
			float sr = halfPI / sides;
			for (int i = 0; i <= sides; i++)
			{
				float angle = -(halfPI + i * sr);
				float x = cos(angle) * radiusX;
				float y = sin(angle) * radiusX;
				points.append(centerLeftBottom + BPointf(x, -y));
			}
		}
		else
		{
			float rx2 = radiusX * radiusX;
			float ry2 = radiusY * radiusY;
			for (float x = 0; x > -radiusX; x -= 2)
			{
				float y = sqrt((1 - (x * x) / rx2) * ry2);
				points.append(centerLeftBottom + BPointf(x, y));
			}
			points.append(centerLeftBottom + BPointf(-radiusX, 0));
		}
	}
}
void IRound::createRightTopPoints(const BRectf& rect, BPointfArray& points)
{
	float radiusX = (float)(radiusRightTop.width() - (widgetSize.width() - rect.right()));
	float radiusY = (float)(radiusRightTop.height() - rect.top());
	if (radiusX <= 0 || radiusY <= 0)
	{
		points.append(rect.rightTop());
	}
	else
	{
		if (radiusX == radiusY)
		{
			int sides = (int)bLimit(radiusX / 3, 3, 24);
			float sr = halfPI / sides;
			for (int i = 0; i <= sides; i++)
			{
				float angle = halfPI - i * sr;
				float x = cos(angle) * radiusX;
				float y = sin(angle) * radiusX;
				points.append(centerRightTop + BPointf(x, -y));
			}
		}
		else
		{
			float rx2 = radiusX * radiusX;
			float ry2 = radiusY * radiusY;
			for (float x = 0; x < radiusX; x += 2)
			{
				float y = sqrt((1.0f - (x * x) / rx2) * ry2);
				points.append(centerRightTop + BPointf(x, -y));
			}
			points.append(centerRightTop + BPointf(radiusX, 0));
		}
	}
}
void IRound::createRightBottomPoints(const BRectf& rect, BPointfArray& points)
{
	float radiusX = (float)(radiusRightBottom.width() - (widgetSize.width() - rect.right()));
	float radiusY = (float)(radiusRightBottom.height() - (widgetSize.height() - rect.bottom()));
	if (radiusX <= 0 || radiusY <= 0)
	{
		points.append(rect.rightBottom());
	}
	else
	{
		if (radiusX == radiusY)
		{
			int sides = (int)bLimit(radiusX / 3, 3, 24);
			float sr = halfPI / sides;
			for (int i = 0; i <= sides; i++)
			{
				float angle = -i * sr;
				float x = cos(angle) * radiusX;
				float y = sin(angle) * radiusX;
				points.append(centerRightBottom + BPointf(x, -y));
			}
		}
		else
		{
			float rx2 = radiusX * radiusX;
			float ry2 = radiusY * radiusY;
			for (float x = radiusX; x > 0; x -= 2)
			{
				float y = sqrt((1 - (x * x) / rx2) * ry2);
				points.append(centerRightBottom + BPointf(x, y));
			}
			points.append(centerRightBottom + BPointf(0, radiusY));
		}
	}
}
void IRound::createTriangles(const BPointfArray& pointsA, const BPointfArray& pointsB, BPointfArray& points)
{
	points.reset();
	if (pointsB.size() == 1)
	{
		const BPointf center = pointsB[0];
		int sizeA = pointsA.size() - 1;
		for (int i = 0; i < sizeA; i++)
		{
			points.append(center);
			points.append(pointsA[i]);
			points.append(pointsA[i + 1]);
		}
		return;
	}
	int indexA = 0;
	int indexB = 0;
	int sizeA = pointsA.size() - 1;
	int sizeB = pointsB.size() - 1;
	while (indexA < sizeA || indexB < sizeB)
	{
		points.append(pointsA[indexA]);
		points.append(pointsB[indexB]);
		if (indexA == sizeA)
		{
			points.append(pointsB[++indexB]);
			break;
		}
		if (indexB == sizeB)
		{
			points.append(pointsA[++indexA]);
			break;
		}
		float lenA2 = (pointsA[indexA + 1] - pointsB[indexB]).length2();
		float lenB2 = (pointsB[indexB + 1] - pointsA[indexA]).length2();
		if (lenA2 < lenB2)
		{
			points.append(pointsA[++indexA]);
		}
		else
		{
			points.append(pointsB[++indexB]);
		}
	}
}
